/*
 * GraphicUserInterface.cpp
 *
 *  Created on: 06/10/2011
 *      Author: mario
 */

#include "GraphicUserInterface.h"
#include <stdio.h>

#include "../control/ElectionManager.h"
#include "../control/CargoDao.h"
#include "../control/CandidatoDao.h"
#include "../control/VotanteDao.h"
#include "../control/EleccionDao.h"
#include "../control/ListaDao.h"
#include "../control/DistritoDao.h"

#include "../../util/NodoEleccion.h"
#include "../../util/NodoLista.h"
#include "../../util/NodoCargo.h"
#include "../../util/NodoCandidato.h"
#include "../../util/NodoConteo.h"
#include "../../util/NodoDistrito.h"
#include "../../util/List.h"

#include "../Eleccion.h"
#include "../Lista.h"
#include "../Candidato.h"
#include "../loader/CsvLoader.h"
#include "../control/UserManager.h"
#include "../AI/bot.h"

#include "../RSA/RSAEncryption.h"
#include "../RSA/Wiener.h"

GraphicUserInterface::GraphicUserInterface() {

}

GraphicUserInterface::~GraphicUserInterface() {

}

string getNotEmptyUserInput(string label) {
       string input = "";
       while (input.length() == 0) {
		   cout << label;
		   getline(cin, input);
       }
       return input;
}

int spacer() {
	int i;

	for (i = 0; i < SEPARATION; i++)
		cout << '\n';

	return 0;
}

void printHeader(string msg) {
	cout << SPACER;
	cout << msg;
	cout << SPACER;
	cout << '\n';

}

void printMainMenu() {
	printHeader("                       MENU PRINCIPAL                      \n");

	cout << "   1- Ingreso Usuario\n";
	cout << "   2- Administracion\n";
	cout << "   3- Salir\n";

	cout << '\n';
	cout << SPACER;
	cout << "Su eleccion: ";
}

void printReportAdminMenu() {
	printHeader("                       MENU DE REPORTES                      \n");

	cout << "   1- Generar Reporte\n";
	cout << "   2- Ver ultimo reporte desencriptado\n";
	cout << "   3- Ver ultimo reporte encriptado\n";
	cout << "   4- Atacar ultimo reporte con Kasiski\n";
	cout << "   5- Salir\n";

	cout << '\n';
	cout << SPACER;
	cout << "Su eleccion: ";
}


void printMainAdminMenu() {
	printHeader("                       MENU DE ADMINISTRACION                      \n");

	cout << "   1- Administracion\n";
	cout << "   2- Correr Simulacion\n";
	cout << "   3- Reportes\n";
	cout << "   4- Atacar RSA con Wiener\n";
	cout << "   5- Salir\n";

	cout << '\n';
	cout << SPACER;
	cout << "Su eleccion: ";
}


void printEntityAdminMenu() {
	printHeader("                       Administracion                   \n");

	cout << "   1- Distritos\n";
	cout << "   2- Votantes\n";
	cout << "   3- Elecciones\n";
	cout << "   4- Cargos\n";
	cout << "   5- Listas\n";
	cout << "   6- Candidatos\n";
	cout << "   7- Atras\n";

	cout << '\n';
	cout << SPACER;
	cout << "Su eleccion: ";
}

void manageEntityTree(string treeName, char command, string file) {

	CsvLoader* l = CsvLoader::getInstance();
	l->loadCsv(command, file);
}

void manageEntities(int entityType, string input) {

	string treeToModify;
	char command;
	string file;

	command = input[0];
	file = input.substr(input.find(" ")+1,input.length());

	switch (entityType) {
		case GraphicUserInterface::DISTRITOS_OP:
			treeToModify = DISTRITOS;
			break;
		case GraphicUserInterface::VOTANTES_OP:
			treeToModify = VOTANTES;
			break;
		case GraphicUserInterface::ELECCIONES_OP:
			treeToModify = ELECCIONES;
			break;
		case GraphicUserInterface::CARGOS_OP:
			treeToModify = CARGOS;
			break;
		case GraphicUserInterface::LISTAS_OP:
			treeToModify = LISTAS;
			break;
		case GraphicUserInterface::CANDIDATOS_OP:
			treeToModify = CANDIDATOS;
			break;
		default:
			break;
	}

		manageEntityTree(treeToModify, command, file);

}

void entitiesAdminBatch(int entityType) {
	string input;
	string edition;
	do {
		do {
			cout << "\nIngrese el codigo de operacion seguido del archivo de trabajo ('a','b','m' + archivo): ";
			getline(cin, input);
		} while (input.length() <= 0);
		try{
			manageEntities(entityType, input);
			cout << "Operacion finalizada. \n";
			cout << "Desea realizar una nueva operacion? [S/N]: ";
			getline(cin, edition);
		}catch(CustomException e){
				cout<<"El archivo ingresado no existe"<<endl;
		}

	} while(edition != "N" && edition != "n");
}

void printEntityManualMenu(bool bajaDisponible) {
	cout << SPACER;
	cout << "   1- Alta\n";
	cout << "   2- Modificacion\n";

	if (bajaDisponible) {
		cout << "   3- Baja\n";
	}
	cout << '\n';
	cout << SPACER;
	cout << "Su eleccion: ";
}

int selectCargo() {
	List* cargos = CargoDao::returnAll();
	int* ids = new int[cargos->getSize()];

	for (int i=0; i<cargos->getSize(); i++) {
		Cargo* c = ((NodoCargo*)cargos->get(i))->getNodeValue();
		cout << c->getId() << " - " << c->getTitulo() << endl;
		ids[i] = c->getId();
	}

	bool idValid = false;
	int id;
	do {
		cout << "Ingrese el cargo: ";
		string input;
		getline(cin,input);
		id = Utils::stringToInt(input);

		for (int j=0; j<cargos->getSize(); j++) {
			if (ids[j] == id) {
				idValid = true;
				break;
			}
		}
		if (!idValid) {
			cout << "Cargo incorrecto." << endl;;
		}
	} while (!idValid);

	return id;
}


int selectDistrito() {
	List* distritos = DistritoDao::returnAll();
	int* ids = new int[distritos->getSize()];

	for (int i=0; i<distritos->getSize(); i++) {
		Distrito* d = ((NodoDistrito*)distritos->get(i))->getNodeValue();
		cout << d->getId() << " - " << d->getNombre() << endl;
		ids[i] = d->getId();
	}

	bool idValid = false;
	int id;
	do {
		cout << "Ingrese el distrito: ";
		string input;
		getline(cin,input);
		id = Utils::stringToInt(input);

		for (int j=0; j<distritos->getSize(); j++) {
			if (ids[j] == id) {
				idValid = true;
				break;
			}
		}
		if (!idValid) {
			cout << "Distrito incorrecto." << endl;;
		}
	} while (!idValid);

	return id;
}

int selectEleccion(){
	List* elecciones = EleccionDao::returnAll();
	int* ids = new int[elecciones->getSize()];

	for (int i=0; i<elecciones->getSize(); i++) {
		Eleccion* e = ((NodoEleccion*)elecciones->get(i))->getNodeValue();
		cout << e->getId() << " - " << e->getFecha() << endl;
		ids[i] = e->getId();
	}

	bool idValid = false;
	int id;
	do {
		cout << "Ingrese la eleccion: ";
		string input;
		getline(cin,input);
		id = Utils::stringToInt(input);

		for (int j=0; j<elecciones->getSize(); j++) {
			if (ids[j] == id) {
				idValid = true;
				break;
			}
		}
		if (!idValid) {
			cout << "Eleccion incorrecta." << endl;;
		}
	} while (!idValid);

	return id;
}


int selectLista() {
	List* listas = ListaDao::returnAll();
	int* ids = new int[listas->getSize()];

	for (int i=0; i<listas->getSize(); i++) {
		Lista* l = ((NodoLista*)listas->get(i))->getNodeValue();
		cout << l->getId() << " - " << l->getNombre() << endl;
		ids[i] = l->getId();
	}

	bool idValid = false;
	int id;
	do {
		cout << "Ingrese la lista: ";
		string input;
		getline(cin,input);
		id = Utils::stringToInt(input);

		for (int j=0; j<listas->getSize(); j++) {
			if (ids[j] == id) {
				idValid = true;
				break;
			}
		}
		if (!idValid) {
			cout << "Lista incorrecta." << endl;;
		}
	} while (!idValid);

	return id;
}

int selectCandidato() {
	List* candidatos = CandidatoDao::returnAll();
	int* ids = new int[candidatos->getSize()];

	for (int i=0; i<candidatos->getSize(); i++) {
		Candidato* c = ((NodoCandidato*)candidatos->get(i))->getNodeValue();
		cout << c->getId() << " -  Lista " <<  c->getLista()->getNumeroLista() << " " << c->getCargo()->getTitulo()   << endl;
		ids[i] = c->getId();
	}

	bool idValid = false;
	int id;
	do {
		cout << "Ingrese la lista: ";
		string input;
		getline(cin,input);
		id = Utils::stringToInt(input);

		for (int j=0; j<candidatos->getSize(); j++) {
			if (ids[j] == id) {
				idValid = true;
				break;
			}
		}
		if (!idValid) {
			cout << "Lista incorrecta." << endl;;
		}
	} while (!idValid);

	return id;
}

void cargosAdminManual() {
	printEntityManualMenu(false);
	string input;

	getline(cin, input);
	int option = Utils::stringToInt(input);
	Cargo* cargo;
	string nombreTitulo = "";
	CargoDao* cargoDao = new CargoDao();
	int cargoId;
	int ret;
	switch (option) {
		case 1:
			nombreTitulo = getNotEmptyUserInput("Ingrese el nombre del cargo: ");
			cargo = Cargo::create(-1, nombreTitulo);
			ret = cargoDao->addCargo(cargo);
			break;
		case 2:
			cargoId = selectCargo();
			nombreTitulo = getNotEmptyUserInput("Ingrese el nuevo nombre del cargo: ");
			cargo = Cargo::create(cargoId, nombreTitulo);
			ret = cargoDao->modifyCargo(cargo);
			break;
		default:
			break;
	}
}



void eleccionesAdminManual() {
	printEntityManualMenu(false);
	string input;
	int distritoId;
	int cargoId;

	getline(cin, input);
	int option = Utils::stringToInt(input);
	Eleccion* eleccion;
	Distrito* distrito;
	Cargo* cargo;
	string fecha = "";
	EleccionDao* eleccionDao = new EleccionDao();

	switch (option) {
		case 1:
			fecha = getNotEmptyUserInput("Ingrese la fecha de la eleccion (dd/mm/aaaa): ");
			distritoId = selectDistrito();
			cargoId = selectCargo();
			distrito = Distrito::create(distritoId);
			cargo = Cargo::create(cargoId);
			eleccion = Eleccion::create(-1, cargo, distrito, fecha);
			eleccionDao->addEleccion(eleccion);
			break;
		case 2:
			cargoId = selectEleccion();
			fecha = getNotEmptyUserInput("Ingrese la nueva fecha de la eleccion (dd/mm/aaaa): ");
			eleccionDao->modifyEleccion(cargoId, fecha);
			break;
		default:
			break;
	}
}

void votantesAdminManual() {

	UserManager* userManager = new UserManager();
	printEntityManualMenu(true);
	string input;
	int distritoId;
	getline(cin, input);
	int option = Utils::stringToInt(input);

	if (option > 0 && option < 4) {
		Distrito* distrito;
		Votante* votante;
		int dni;
		string dniValue = "";
		string nombre = "";
		string apellido = "";
		string password = "";
		dniValue = getNotEmptyUserInput("Ingrese el DNI del votante: ");

		dni = Utils::stringToInt(dniValue);
		switch (option) {
			case 1:
				votante = userManager->searchUser(dni);
				if (votante != NULL) {
					cout << "El Votante ya se encuentra registrado." << endl;
				}else{
					nombre = getNotEmptyUserInput("Ingrese el nombre del votante: ");
					apellido = getNotEmptyUserInput("Ingrese el apellido del votante: ");
					password = getNotEmptyUserInput("Ingrese el password del votante: ");
					distritoId = selectDistrito();
					distrito = Distrito::create(distritoId);
					votante = Votante::create(dni,nombre,apellido,password,distrito, NULL);
					userManager->addUser(votante);
				}
				break;
			case 2:
				votante = userManager->searchUser(dni);
				if (votante != NULL) {
					cout << "Ingrese el nuevo nombre del votante: ";
					getline(cin, nombre);
					cout << "Ingrese el apellido del votante: ";
					getline(cin, apellido);
					cout << "Ingrese el password del votante: ";
					getline(cin, password);
					distritoId = selectDistrito();
					votante->modify(nombre,apellido,password);
					userManager->saveUser(votante);
				}
				else {
					cout << "Votante no existente." << endl;;
				}
				break;
			case 3:
				votante = userManager->searchUser(dni);
				if (votante != NULL) {
					userManager->deleteUser(votante);
					cout << "Votante eliminado." << endl;
				}
				else {
					cout << "Votante no existente." << endl;;
				}
				break;
			default:
				break;
		}
	}
}

void distritosAdminManual(){

	printEntityManualMenu(false);
	string input;
	getline(cin, input);
	int option = Utils::stringToInt(input);

	DistritoDao* distritoDao = new DistritoDao();

	int id;
	Distrito* distrito;
	string nombre = "";


	switch (option) {
		case 1:
			nombre = getNotEmptyUserInput("Ingrese el nombre del distrito: ");
			distrito = Distrito::create(0, nombre);
			distritoDao->addDistrito(distrito);
			free(distrito);
			break;
		case 2:
			id = selectDistrito();
			distrito = distritoDao->searchDistrito(id);
			if (distrito != NULL) {
				nombre = getNotEmptyUserInput("Ingrese el nuevo nombre del distrito: ");
				distrito->setNombre(nombre);
				distritoDao->saveDistrito(distrito);
			}
			else {
				cout << "Distrito no existente." << endl;;
			}
			free(distrito);
			break;
		default:
			break;

	}
}

void listasAdminManual(){

	printEntityManualMenu(false);
	string input;
	getline(cin, input);
	int option = Utils::stringToInt(input);

	ListaDao* listaDao = new ListaDao();

	int id;
	Lista* lista;
	string nombre = "";
	int numeroLista = 0;
	int eleccionId = 0;
	Eleccion* eleccion = NULL;
	string numeroListaValue;

	switch (option) {
		case 1:
			numeroListaValue = getNotEmptyUserInput("Ingrese el numero de la lista: ");
			numeroLista = Utils::stringToInt(numeroListaValue);
			nombre = getNotEmptyUserInput("Ingrese el nombre de la lista: ");
			eleccionId = selectEleccion();
			eleccion = Eleccion::create(eleccionId);

			lista = Lista::create(0, numeroLista, nombre, eleccion, new List());
			listaDao->addLista(lista);
			free(lista);
			break;
		case 2:
			id = selectLista();
			lista = listaDao->searchLista(id);
			if (lista != NULL) {
				numeroListaValue = getNotEmptyUserInput("Ingrese el nuevo numero de la lista: ");
				numeroLista = Utils::stringToInt(numeroListaValue);
				nombre = getNotEmptyUserInput("Ingrese el nuevo nombre de la lista: ");
				lista->setNumeroLista(numeroLista);
				lista->setNombre(nombre);
				listaDao->saveLista(lista);
			}
			else {
				cout << "Lista no existente." << endl;;
			}
			free(lista);
			break;
		default:
			break;
	}

}

void candidatosAdminManual(){

	cout << "Alta" << endl;

	CandidatoDao* candidatoDao = new CandidatoDao();
	ListaDao* listaDao = new ListaDao();
	UserManager* userManager = new UserManager();

	string dniValue;
	int dni;
	Candidato* candidato;
	Votante* votante;
	int cargoId;
	Cargo* cargo;
	int listaId;
	Lista* lista;

	dniValue = getNotEmptyUserInput("Ingrese el Numero del DNI: ");
	dni = Utils::stringToInt(dniValue);
	votante = userManager->searchUser(dni);

	if(votante != NULL)
	{
		cargoId = selectCargo();
		cargo = Cargo::create(cargoId);

		listaId = selectLista();
		lista = listaDao->searchLista(listaId);

		candidato = Candidato::create(0, votante, lista, cargo);
		candidatoDao->addCandidato(candidato);

		NodoCandidato* nodoCandidato = new NodoCandidato();
		nodoCandidato->setNodeValue(candidato);
		lista->getCandidatos()->add(nodoCandidato);

		listaDao->saveLista(lista);

		free(lista);
		free(candidato);
	}
	else {
		cout << "Votante no existente." << endl;;
	}
}



void entitiesAdminManual(int entityType) {

	switch (entityType) {
		case GraphicUserInterface::VOTANTES_OP:
			votantesAdminManual();
			break;
		case GraphicUserInterface::DISTRITOS_OP:
			distritosAdminManual();
			break;
		case GraphicUserInterface::ELECCIONES_OP:
			eleccionesAdminManual();
			break;
		case GraphicUserInterface::CARGOS_OP:
			cargosAdminManual();
			break;
		case GraphicUserInterface::LISTAS_OP:
			listasAdminManual();
			break;
		case GraphicUserInterface::CANDIDATOS_OP:
			candidatosAdminManual();
			break;
		default:
			break;
	}
}

void entitiesAdmin(int entityType) {
	int option = -1;
	string input;
	while (option != 3) {
		cout << SPACER;
		cout << "   1- Carga Manual\n";
		cout << "   2- Carga con Archivo CSV\n";
		cout << "   3- Atras\n";
		cout << '\n';
		cout << SPACER;
		cout << "Su eleccion: ";
		getline(cin, input);
		option = Utils::stringToInt(input);

		if (option > 0 && option < 3) {

			switch (option) {

			case 1:
				entitiesAdminManual(entityType);
				break;
			case 2:
				entitiesAdminBatch(entityType);
				break;
			}
		}
	}
}


void electronicVoteAdmin() {
	int option = -1;
	string op;
	while (option != 7) {
		printEntityAdminMenu();

		getline(cin, op);

		option = Utils::stringToInt(op);

		if(option > 0 && option < 7){
			entitiesAdmin(option);
		}

	}
}

void excecuteReport() {
	int d;
	int e;
	int l;

	string salir = "n";

	Eleccion* elecccionSel;
	Distrito* distritoSel;
	Lista* listaSel;
	do{
		d = -1;
		e = -1;
		l = -1;

		printHeader("                       Reportes                   \n");

		string opcion;
		cout << "\nSELECCIONE UNA ELECCION DE LAS DISPONIBLES\n" << endl;
		List* elecciones = EleccionDao::returnAll();
		int size = elecciones->getSize();

		int i = 0;
		for(i = 0; i < size; i++){
			Eleccion* e = ((NodoEleccion*)elecciones->get(i))->getNodeValue();
			cout << i + 1  << " - " + CargoDao::initialize(e->getCargo())->getTitulo() << " - Fecha: " + e->getFecha() << endl;
		}
		int opTodas = i + 1;

		cout << opTodas << " - [TODAS]" << endl;
		cout << SPACER;
		cout << "Su eleccion: ";
		getline(cin, opcion);

		int seleccion = 0;
		bool validate = false;

		while(!validate){
			seleccion = Utils::stringToInt(opcion);
			if(!Utils::validateInteger(opcion) || opcion.empty() || seleccion > opTodas){
				cout << "\n[OPCION INVALIDA]. Intentelo nuevamente:";
				getline(cin, opcion);
			}else{
				validate = true;
			}
		}

		if(seleccion != opTodas) {
			elecccionSel = ((NodoEleccion*)elecciones->get(seleccion - 1))->getNodeValue();
			e = elecccionSel->getId();
		}

		////////////DISTRITO

		cout << "\nSELECCIONE UN DISTRITO DE LOS DISPONIBLES\n" << endl;
		List* distritos = DistritoDao::returnAll();
		size = distritos->getSize();

		i = 0;
		for(i = 0; i < size; i++){
			Distrito* dis = ((NodoDistrito*)distritos->get(i))->getNodeValue();
			cout << i + 1  << " - " + dis->getNombre() << endl;
		}
		opTodas = i + 1;

		cout << opTodas << " - [TODAS]" << endl;
		cout << SPACER;
		cout << "Su eleccion: ";
		getline(cin, opcion);

		seleccion = 0;
		validate = false;

		while(!validate){
			seleccion = Utils::stringToInt(opcion);
			if(!Utils::validateInteger(opcion) || opcion.empty() || seleccion > opTodas){
				cout << "\n[OPCION INVALIDA]. Intentelo nuevamente:";
				getline(cin, opcion);
			}else{
				validate = true;
			}
		}

		if(seleccion != opTodas) {
			distritoSel = ((NodoDistrito*)distritos->get(seleccion - 1))->getNodeValue();
			d = distritoSel->getId();
		}

		//////////// LISTA

		cout << "\nSELECCIONE UNA LISTA DE LAS DISPONIBLES\n" << endl;
		List* listas = ListaDao::returnAll();
		size = listas->getSize();

		i = 0;
		for(i = 0; i < size; i++){
			Lista* lis = ((NodoLista*)listas->get(i))->getNodeValue();
			cout << i + 1  << " - " << lis->getNumeroLista() << " - " + lis->getNombre() << endl;
		}
		opTodas = i + 1;

		cout << opTodas << " - [TODAS]" << endl;
		cout << SPACER;
		cout << "Su eleccion: ";
		getline(cin, opcion);

		seleccion = 0;
		validate = false;

		while(!validate){
			seleccion = Utils::stringToInt(opcion);
			if(!Utils::validateInteger(opcion) || opcion.empty() || seleccion > opTodas){
				cout << "\n[OPCION INVALIDA]. Intentelo nuevamente:";
				getline(cin, opcion);
			}else{
				validate = true;
			}
		}

		if(seleccion != opTodas) {
			listaSel = ((NodoLista*)listas->get(seleccion - 1))->getNodeValue();
			l = listaSel->getId();
		}


		if(d > -1 || l > -1 || e > -1){
			int total = ResultManager::getReportValue(d, e, l);
			cout << "\n";
			cout << SPACER;

			stringstream ss(ios_base::in| ios_base::out| ios_base::binary);

			ss << "Para: " << endl;;
			if(e > -1){
				ss << CargoDao::initialize(elecccionSel->getCargo())->getTitulo() << " - Fecha: " + elecccionSel->getFecha() << endl;
			}
			if(d > -1){
				ss << distritoSel->getNombre() << endl;
			}
			if(l > -1){
				ss << "Lista " << listaSel->getNumeroLista() << " - " + listaSel->getNombre() << endl;
			}
			ss << '\n';
			ss << SPACER;
			ss << "Total de Votos: " << total << endl;
			ss << SPACER;
			ss << "\n";

			cout << ss.str();
			ResultManager::writeReportFile(&ss);
			//cout << ResultManager::readReportFile() << endl;

		}else{
			cout << "\n[CRITERIO DE BUSQUEDA INVÁLIDO]. Debe ingresa al menos una de las opciones.\n";
		}

		do{
			cout << "Desea realizar una nueva operacion? [S/N]: ";
			getline(cin, salir);
		}while(salir != "N" && salir != "n" && salir != "S" && salir != "s");


		delete elecciones;
		delete distritos;
		delete listas;

	}while(salir != "N" && salir != "n");
}

int confirmarVoto(ElectionManager* electionManager, Lista* lista){
	printHeader("                CONFIRME SU VOTO                \n");

	Eleccion* eleccion = EleccionDao::initialize(lista->getEleccion());
	Cargo * cargo = CargoDao::initialize(eleccion->getCargo());
	cout << "Cargo: " << cargo->getTitulo() << endl;
	cout << "Numero de Lista: " << lista->getNumeroLista() << endl;
	cout << "Partido: " << lista->getNombre() << endl;
	cout << "Candidatos:" << endl;

	List* candidatos = lista->getCandidatos();

	for(int i = 0; i < candidatos->getSize(); i++){
		Candidato* c = ((NodoCandidato*)candidatos->get(i))->getNodeValue();
		c = CandidatoDao::initialize(c);
		cout << "\t" + VotanteDao::initialize(c->getVotante())->getFullName() << endl;
	}

	cout << "\n";

	string confirmacion;
	do{
		cout << "Por favor, confirme su voto[S/N]: ";
		getline(cin, confirmacion);
	}while(confirmacion != "S" && confirmacion != "s" && confirmacion != "N" && confirmacion != "n");

	if(confirmacion == "S" || confirmacion == "s"){
		Logger::createEntryLog(Utils::intToString(electionManager->getUser()->getDni())+" VOTO CONFIRMADO",Logger::LOG);
		return electionManager->confirmVote(lista);
	}
	Logger::createEntryLog(Utils::intToString(electionManager->getUser()->getDni())+" CANCELA VOTO",Logger::LOG);
	return -2;
}

/**
 *
 */
void selectLista(ElectionManager* electionManager) {
		string listOption;
		string logout;
		do{
			printHeader("                INDIQUE LA LISTA A LA QUE DESEA VOTAR                \n");

			List* listas = electionManager->getListasDisponibles();
			int nListas = listas->getSize();
			if(nListas == 0) {
				cout << "NO HAY NINGUNA LISTA HABILITADA REGISTRADA PARA LA ELECCION SELECCIONADA." << endl;
			}
			int i = 0;
			for(i = 0; i < nListas; i++){
				Lista* l = ((NodoLista*)listas->get(i))->getNodeValue();
				cout << i + 1  << " - " << " Lista " <<  l->getNumeroLista() << " - " + l->getNombre() << endl;
			}
			int opSalir = i + 1;

			cout << opSalir << " - [SALIR]" << endl;
			cout << SPACER;
			cout << "Su eleccion: ";
			getline(cin, listOption);

			int seleccion = 0;
			bool validate = false;

			while(!validate){
				seleccion = Utils::stringToInt(listOption);
				if(!Utils::validateInteger(listOption) || listOption.empty() || seleccion > opSalir){
					cout << "\n[OPCION INVALIDA]. Intentelo nuevamente:";
					getline(cin, listOption);
				}else {
					validate = true;
				}
			}
			if(seleccion == opSalir){
				logout = "n";
				delete listas;
			}else{
				cout << "\n";
				Logger::createEntryLog(Utils::intToString(electionManager->getUser()->getDni())+" VOTO",Logger::LOG);
				Lista* selList = ((NodoLista*)listas->get(seleccion - 1))->getNodeValue();
				int resultado = confirmarVoto(electionManager, selList);
				if(resultado == 0){
					Logger::createEntryLog(Utils::intToString(electionManager->getUser()->getDni())+" VOTO CONFIRMADO",Logger::LOG);
					logout = "n";
					delete listas;
				}
				else{
					Logger::createEntryLog(Utils::intToString(electionManager->getUser()->getDni())+" CAMBIO VOTO",Logger::LOG);
				}
			}

		}while(logout != "N" && logout != "n");
}

/**
 *
 */
void selectVotarEleccion(ElectionManager* electionManager) {
		string electionOption;
		string logout;
		do{
			printHeader("    SELECCIONE LA ELECCION DE LA CUAL DESEA PARTICIPAR                \n");

			List* elecciones = electionManager->getEleccionesDisponibles();
			int nElecciones = elecciones->getSize();
			if(nElecciones == 0) {
				cout << "ACTUALMENTE NO USTED NO TIENE NINGUNA ELECCION DISPONIBLE PARA VOTAR." << endl;
			}
			int i = 0;
			for(i = 0; i < nElecciones; i++){
				Eleccion* el = ((NodoEleccion*)elecciones->get(i))->getNodeValue();
				cout << i + 1  << " - " <<  CargoDao::initialize(el->getCargo())->getTitulo() << endl;
			}
			int opSalir = i + 1;

			cout << opSalir << " - [SALIR]" << endl;
			cout << SPACER;
			cout << "Su eleccion: ";
			getline(cin, electionOption);

			int seleccion = 0;
			bool validate = false;

			while(!validate){
				seleccion = Utils::stringToInt(electionOption);
				if(!Utils::validateInteger(electionOption) || electionOption.empty() || seleccion > opSalir){
					cout << "\n[OPCION INVALIDA]. Intentelo nuevamente:";
					getline(cin, electionOption);
				}else{
					validate = true;
				}
			}
			if(seleccion == opSalir){
				electionManager->resetEleccion();
				logout = "n";
			}else{
				cout << "\n";
				int result = electionManager->selectEleccion(((NodoEleccion*)elecciones->get(seleccion - 1))->getNodeValue());
				if(result != 1){
					Logger::createEntryLog("ERROR INESPERADOAL SELECCIONAR UNA ELECCION ",Logger::ERROR);
					logout = "n";
				}else{
					selectLista(electionManager);
					logout = "n";
				}
			}
			delete elecciones;

		}while(logout != "N" && logout != "n");
}

/**
 *
 */
void login(ElectionManager* electionManager) {
	string usuario;
	string password;
	string logout;
	do{
		printHeader("            INGRESO AL SISTEMA DE VOTO ELECTRONICO                \n");

		cout << "\nNombre de Usuario: ";
		getline(cin, usuario);

		cout << "Contraseña: ";
		getline(cin, password);

		int usrId = Utils::stringToInt(usuario);
		int loginResult = electionManager->login(usrId,password);

		if(loginResult != 1){
			do {
				Logger::createEntryLog("USUARIO O CONTRASEÑA INVALIDO",0);
				cout << "\n\nUSUARIO O CONTRASEÑA INVALIDO \n";
				cout << "Desea intentarlo nuevamente? [S/N]: ";
				getline(cin, logout);
			}while(logout != "N" && logout != "n" && logout != "S" && logout != "s");

		}else{

			Logger::createEntryLog(Utils::intToString(electionManager->getUser()->getDni())+" LOGIN",Logger::LOG);

			cout << "\n";
			selectVotarEleccion(electionManager);
			logout = "N";
			electionManager->logout();
		}

	}while(logout != "N" && logout != "n");
}

void runSimulation(){
	printHeader("                 Simulacion Elecciones                   \n");
	bot* b = new bot();
	int result = b->runSimulation();
	if(result == 0){
		cout << "La simulacion termino correctamente" << endl;
	}else{
		cout << "La simulacion termino con errores" << endl;
	}
}

void runRSAAttack(){

	bool brokenOnce = false;
	do{
		cout << "\nInicializando incriptador RSA..." << endl;
		RSAEncryption* rsa = RSAEncryption::newInstance();

		Wiener::PublicKey publickKey;

		long int e = rsa->getE();
		int N = rsa->getN();

		cout << "\nRSA inicializado con:" << endl;
		cout << "\n";
		cout << "d is:" << rsa->getD() << endl;
		cout << "p is:" << rsa->getP() << endl;
		cout << "q is:" << rsa->getQ() << endl;


		publickKey.e = e;
		publickKey.N = N;

		cout << "\nAtacando la clave publica" ;
		cout << " N: " << publickKey.N;
		cout << " e: " << publickKey.e;
		cout << " con el metodo de Wiener" << endl;

		Wiener* wiener = new Wiener();
		Wiener::Result result = wiener->attack(publickKey);


		if (result.succeded)
		{
			cout << "\nComponentes da la clave: " << endl;
			cout << "\n";
			cout << "d: " << result.d << endl;
			cout << "p: " << result.p << endl;
			cout << "q: " << result.q << endl;
			cout << "phi(N): " << result.phi << endl;
			brokenOnce = true;
		}
		else
		{
			cout << "\nNo se pudo romper la clave" << endl;
		}
		delete rsa;
		delete wiener;
	}while (!brokenOnce);
}

void showReportMenu() {
	int option = 0;
	string op;

	while (option != 5) {

		printReportAdminMenu();
		getline(cin, op);
		option = Utils::stringToInt(op);

		switch (option) {
				case 1:
					excecuteReport();
					break;
				case 2:
					cout << ResultManager::readReportFile() << endl;
					break;
				case 3:
					cout << ResultManager::readEncryptedReportFile() << endl;
					break;
				case 4:
					ResultManager::kasiskiAttack();
					break;
				default:
					break;
		}
	}
}

/**
 *
 */
void admin(ElectionManager* electionManager){
	int option;
		string op;
		int logout = 0;

		while (logout != 1) {

			printMainAdminMenu();

			getline(cin, op);

			option = Utils::stringToInt(op);

			switch (option) {

			case 1:
				electronicVoteAdmin();
				break;
			case 2:
				runSimulation();
				break;
			case 3:
				showReportMenu();
				//excecuteReport();
				break;
			case 4:
				runRSAAttack();
				break;
			case 5:
				logout = 1;
				break;
			default:
				break;

			}
		}
}

/**
 *
 */
void GraphicUserInterface::menu() {
	int option;
	string op;
	int logout = 0;

	ElectionManager* electionManager = new ElectionManager();

	while (logout != 1) {
		Logger::createEntryLog("INGRESO AL SISTEMA",Logger::LOG);
		printMainMenu();

		getline(cin, op);

		option = Utils::stringToInt(op);

		switch (option) {

		case 1:
			Logger::createEntryLog("VOTANTE INGRESA A LOGIN",Logger::LOG);
			login(electionManager);
			break;
		case 2:
			Logger::createEntryLog("ADMINISTRADOR",Logger::LOG);
			admin(electionManager);
			break;
		case 3:
			Logger::createEntryLog("SALIDA DEL SISTEMA",Logger::LOG);
			logout = 1;
			break;

		default:
			break;

		}
	}
	delete electionManager;

}

